package com.yunhe.dtu.task.task;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yunhe.common.util.*;
import com.yunhe.dtu.constant.HttpConstant;
import com.yunhe.dtu.domain.Data;
import com.yunhe.dtu.util.BigDecimalUtil;
import com.yunhe.dtu.util.MapUtil;
import com.yunhe.dtu.util.YmlUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.script.ScriptException;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @ClassName DtuDataTask
 * @Description 获取dtu采集数据定时任务
 * @Author HeTao
 * @Date 2020/11/16 13:39
 * @Version 1.0
 **/
@Service
public class DtuDataTask {

    private static Logger log = LoggerFactory.getLogger(DtuDataTask.class);

    /**
     * 数据集合
     */
    private static LinkedBlockingQueue<String> dataListBOQueue = new LinkedBlockingQueue<>();

    @Autowired
    private RedisClient redisClient;

    @Value("${dtu.host}")
    private  String host;

    @Value("${dtu.path}")
    private  String path ;

    @Value("${dtu.acceseeToken}")
    private  String acceseeToken ;

    @Value("${dtu.count}")
    private  String count ;

    @Value("${dtu.size}")
    private  int SIZE ;

    @Value("${dtu.maxSize}")
    private  int MAXSIZE ;

    private  List<String> list = new ArrayList<>();

    @Value("${dtu.controlYmlPath}")
    private  String controlYmlPath ;

    @Value("${dtu.pointMapYmlPath}")
    private  String pointMapYmlPath ;

    List<String> bAreaBus = Arrays.asList("0f02ab20","0f02ab21");

    //"0f02ae20","0f02ae21",
    List<String> aAreaBus = Arrays.asList("0f02ae22");

    //,"0f02ce21","0f02ce22"
    List<String> hengYunAreaBus = Arrays.asList("0f02ce20");

    List<String> jinwangAreaBus =Arrays.asList(
            "0f02a320",
            "0f02a321",
            "0f02a322",
            "0f02a323",
            "0f02a324",
            "0f02ba20",
            "0f02ba21",
            "0f02ba22",
            "0f02ba23",
            "0f02ba24",
            "0f02bb20",
            "0f02bb21",
            "0f02ee20",
            "0f02bc20",
            "0f02bc21",
            "0f02bc22",
            "0f02bc23",
            "0f02bc24",
            "0f02bc25",
            "0f02ec20",
            "0f02ec21",
            "0f02ec22",
            "0f02ec23",
            "0f02ec24",
            "0f02b320",
            "0f02b321"
    );



    public  void getDtuRealTimeCollectData() throws InterruptedException {
        long startTime = System.currentTimeMillis();

        //创建线程池 批量处理数据
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.submit(() -> {
            batchDataProcessing();
        });

        List<String> sids = YmlUtils.getFirstYmlByFileName(controlYmlPath);
        if(!CollectionUtil.isEmpty(sids)){
            //过滤总线的分线表计
            List<String> collect = sids.stream().filter(s -> {
                return !bAreaBus.contains(s) && !aAreaBus.contains(s) && !hengYunAreaBus.contains(s);
            }).collect(Collectors.toList());
            if(!CollectionUtil.isEmpty(collect)){
                /**
                 * 分批调用dtu采集接口 进行数据收集
                 */
                List<List<String>> streamDatas = new ArrayList<>();
                for (int i = 0; i < collect.size(); i += SIZE) {
                    int j = Math.min((i + SIZE), collect.size());
                    List<String> lists = collect.subList(i, j);
                    streamDatas.add(lists);
                }
                streamDatas.parallelStream().forEach(streamData->{
                    for (String streamDatum : streamData) {
                        httpDtuRequest(streamDatum,count);
                    }
                });
                System.out.println("数据条数"+list.size());
                list.clear();
            }
        }

        dataListBOQueue.add("start");
        executorService.shutdown();
        executorService.awaitTermination(20, TimeUnit.SECONDS);
        long endTime = System.currentTimeMillis();
        System.out.println("数据处理所需时间："+(endTime-startTime));
        log.info("数据处理结束");

    }

    /**
     * 每MAXSIZE条数据处理一次
     */
    private void batchDataProcessing() {
        try {
            for (; ; ) {
                List<String> dataLists = new ArrayList<>(100);
                for (int i = 0; i < MAXSIZE; i++) {
                    String dataStr = dataListBOQueue.take();
                    if (StringUtil.isEmpty(dataStr) || dataStr.equals("start")) {
                        if (!CollectionUtil.isEmpty(dataLists)) {
                            batchDataProcessing(dataLists);
                        }
                        return;
                    } else {
                        dataLists.add(dataStr);
                    }
                }
                if (!CollectionUtil.isEmpty(dataLists)) {
                    batchDataProcessing(dataLists);
                    dataLists.clear();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 批量处理数据
     * @param dataLists
     * @throws ScriptException
     */
    private void batchDataProcessing(List<String> dataLists) throws ScriptException {
        for (String dataList : dataLists) {
            log.info("dtu的整条数据:"+dataList);
            List<Map<String,Object>> maps = (List<Map<String, Object>>) JSON.parse(dataList);
            if(!CollectionUtil.isEmpty(maps)){
                //获取数据 通过sid 查到对应的编号 以及 倍率 以及所映射的点号
                Map<String, Object> map = maps.get(0);
                int size = map.size();
                if(size > 1){
                    String sid = (String) map.get("sid");
                    //获取表号以及倍率配置
                    Map<String, String> controlMap = YmlUtils.getYmlByFileName(controlYmlPath, sid);
                    if(!CollectionUtil.isEmpty(controlMap)){
                        String tableNumber = controlMap.get(sid + ".tableNumber");
                        //推送数据
                        Long time = null;
                        Object update_time = map.get("update_time");
                        if(update_time != null){
                           time = DateTimeUtils.parseDateTime(DateTimeUtils.PATTERN.DATETIME.value(), (String) update_time);
                        }
                        redisClient.setObject(tableNumber, time);
                        //根据对应表号以及数据项生成新的点号，以及查询对应映射的系统点号
                        Map<String, String> pointMap = YmlUtils.getYmlByFileName(pointMapYmlPath, tableNumber);
                        if(!CollectionUtil.isEmpty(pointMap)){
                            for (Map.Entry<String, String> entry : pointMap.entrySet()) {
                                String key = entry.getKey();
                                String pointValue = entry.getValue();
                                //通过对应的key计算相应倍率的值存放在redis
                                calculationAndSaveValue(key,pointValue,map);
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 通过对应的key计算相应倍率的值存放在redis
     * @param key
     * @param pointValue
     * @param dataMap
     */
    private void calculationAndSaveValue(String key,String pointValue,Map<String, Object> dataMap) {
        int i = key.indexOf("_");
        String dataCode = key.substring(i + 1, key.length());
        Object valueStr = dataMap.get(dataCode);
        try {
            Double value = 0d;
            if("p".equals(dataCode)){
                value  = Double.parseDouble(valueStr.toString())/1000;
            }else {
                value = Double.parseDouble(valueStr.toString());
            }
            redisClient.setObject(pointValue,value);
            log.info("当前映射的点号："+pointValue+"的数据项"+dataCode+"的数据值:"+value);
        } catch (Exception e) {
            log.error("数据处理异常",e);
            e.printStackTrace();
        }
    }

    /**
     * 调用dtu 采集接口
     * @param sid
     * @param count
     */
    private  void httpDtuRequest(String sid, String count){
        Map<String,String> headerMap = new HashMap<>();
        headerMap.put("Authorization","Token "+acceseeToken);
        Map<String, String> queryMap = new HashMap<>();
        queryMap.put("sid",sid);
        queryMap.put("count",count);
        try {
            HttpResponse httpResponse = HttpUtil.doGet(host, path, null, headerMap, queryMap);
            int statusCode = httpResponse.getStatusLine().getStatusCode();
            if(HttpConstant.Http_Status.Unauthorized.value()==statusCode){
                log.error(HttpConstant.Http_Status.Unauthorized.title());
            }else if(HttpConstant.Http_Status.NOT_FOUND.value()==statusCode){
                log.error(HttpConstant.Http_Status.NOT_FOUND.title());
            }else if(HttpConstant.Http_Status.INTERNAL_SERVER_ERROR.value()==statusCode){
                log.error(HttpConstant.Http_Status.INTERNAL_SERVER_ERROR.title());
            }else if(HttpConstant.Http_Status.OK.value()==statusCode){
                log.info(HttpConstant.Http_Status.OK.title());
                HttpEntity entity = httpResponse.getEntity();
                String jsonString = EntityUtils.toString(entity);
                if("[]".equals(jsonString)){
                    List<Map<String,String>> maps = new ArrayList<>();
                    Map<String,String> map = new HashMap<>();
                    map.put("sid",sid);
                    maps.add(map);
                    jsonString = JSON.toJSONString(maps);
                }
                list.add(jsonString);
                //System.out.println(jsonString);
                //利用阻塞队列解析数据  用redis 存储
                dataListBOQueue.add(jsonString);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public  void main(String[] args) throws InterruptedException {
        //getDtuRealTimeCollectData();
        String s = redisClient.get("10001002010011686");
        System.out.println(s);
    }

    public Double query(String key) {
        return Double.parseDouble(redisClient.get(key));
    }

    public String  queryData(String sid) {
        Map<String,String> headerMap = new HashMap<>();
        headerMap.put("Authorization","Token "+acceseeToken);
        Map<String, String> queryMap = new HashMap<>();
        queryMap.put("sid",sid);
        queryMap.put("count",count);
        try {
            HttpResponse httpResponse = HttpUtil.doGet(host, path, null, headerMap, queryMap);
            int statusCode = httpResponse.getStatusLine().getStatusCode();
            if(HttpConstant.Http_Status.Unauthorized.value()==statusCode){
                log.error(HttpConstant.Http_Status.Unauthorized.title());
            }else if(HttpConstant.Http_Status.NOT_FOUND.value()==statusCode){
                log.error(HttpConstant.Http_Status.NOT_FOUND.title());
            }else if(HttpConstant.Http_Status.INTERNAL_SERVER_ERROR.value()==statusCode){
                log.error(HttpConstant.Http_Status.INTERNAL_SERVER_ERROR.title());
            }else if(HttpConstant.Http_Status.OK.value()==statusCode){
                log.info(HttpConstant.Http_Status.OK.title());
                HttpEntity entity = httpResponse.getEntity();
                String jsonString = EntityUtils.toString(entity);
                if("[]".equals(jsonString)){
                    List<Map<String,String>> maps = new ArrayList<>();
                    Map<String,String> map = new HashMap<>();
                    map.put("sid",sid);
                    maps.add(map);
                    jsonString = JSON.toJSONString(maps);
                }
                System.out.println("sid的数据:"+jsonString);
                return jsonString;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public void getTotalRealTimeCollectData() {
        //处理总线数据
        List<List<String>>  streamDatas = new ArrayList<>();
        streamDatas.add(aAreaBus);
        streamDatas.add(bAreaBus);
        streamDatas.add(hengYunAreaBus);
        streamDatas.add(jinwangAreaBus);
        List<Data> datas = new ArrayList<>();
        for (List<String> streamData : streamDatas) {
            //某园区总表数据
            Data totalData = new Data();
            if(streamData.containsAll(aAreaBus)){
                totalData.setSid("A");
            }else if(streamData.containsAll(bAreaBus)){
                totalData.setSid("B");
            }else if(streamData.containsAll(hengYunAreaBus)){
                totalData.setSid("HY");
            }else if(streamData.containsAll(jinwangAreaBus)){
                totalData.setSid("JW");
            }
            for (String streamDatum : streamData) {
                Map<String, String> controlMap = YmlUtils.getYmlByFileName(controlYmlPath, streamDatum);
                String josnStr = httpTotalDtuRequest(streamDatum, count);
                log.info("dtu的整条数据:"+josnStr);
                Data data = new Data();
                if(!StringUtil.isEmpty(josnStr)){
                    List<Object> dataList = (List<Object>) JSON.parse(josnStr);
                    if(!CollectionUtil.isEmpty(dataList)){
                        data = JSONObject.parseObject(JSONObject.toJSONString(dataList.get(0)),Data.class);
                        Long time = null;
                        Object update_time = data.getUpdate_time();
                        if(update_time != null){
                            time = DateTimeUtils.parseDateTime(DateTimeUtils.PATTERN.DATETIME.value(), (String) update_time);
                        }
                        redisClient.setObject(controlMap.get(streamDatum+ ".tableNumber"),time);
                    }
                    //处理数据
                    totalData = dealWithData(data,totalData);
                }
            }
            datas.add(totalData);
        }
        //将总线数据存放在redis里面
        putRedis(datas);

    }

    ////将总线数据存放在redis里面
    private void putRedis(List<Data> datas) {
        if(!CollectionUtil.isEmpty(datas)){
            for (Data data : datas) {
                log.info("dtu的整条数据:"+JSON.toJSONString(data));
                data.setE_total(data.getE());
                //根据对应表号以及数据项生成新的点号，以及查询对应映射的系统点号
                Map<String, String> pointMap = YmlUtils.getYmlByFileName(pointMapYmlPath, data.getSid());
                if(!CollectionUtil.isEmpty(pointMap)){
                    for (Map.Entry<String, String> entry : pointMap.entrySet()) {
                        String key = entry.getKey();
                        String pointValue = entry.getValue();
                        //通过对应的key计算相应倍率的值存放在redis
                        //对象转map
                        Map<String, Object> map = MapUtil.JsonToMapNotNull(JSON.toJSONString(data));
                        calculationAndSaveValue(key,pointValue,map);
                    }
                }
            }
        }
    }

    private void calculateYqTotalNum(Data yqData, Data data) {
        //yqData.setp(BigDecimalUtil.add(totalData.getP(),data.getP()))
    }

    //处理总表数据数据
    private Data dealWithData(Data data, Data totalData) {
        totalData.setP(BigDecimalUtil.add(totalData.getP(),data.getP()));
        totalData.setUa(BigDecimalUtil.add(totalData.getUa(),data.getUa()));
        totalData.setIa(BigDecimalUtil.add(totalData.getIa(),data.getIa()));
        totalData.setIb(BigDecimalUtil.add(totalData.getIb(),data.getIb()));
        totalData.setIc(BigDecimalUtil.add(totalData.getIc(),data.getIc()));
        totalData.setE(BigDecimalUtil.add(totalData.getE(),data.getE()));
        totalData.setE_flat(BigDecimalUtil.add(totalData.getE_flat(),data.getE_flat()));
        totalData.setE_peak(BigDecimalUtil.add(totalData.getE_peak(),data.getE_peak()));
        totalData.setE_valley(BigDecimalUtil.add(totalData.getE_valley(),data.getE_valley()));
        totalData.setF(data.getF());
        totalData.setUpdate_time(data.getUpdate_time());
        return totalData;
    }

    private String  httpTotalDtuRequest(String sid, String count) {
        Map<String,String> headerMap = new HashMap<>();
        headerMap.put("Authorization","Token "+acceseeToken);
        Map<String, String> queryMap = new HashMap<>();
        queryMap.put("sid",sid);
        queryMap.put("count",count);
        try {
            HttpResponse httpResponse = HttpUtil.doGet(host, path, null, headerMap, queryMap);
            int statusCode = httpResponse.getStatusLine().getStatusCode();
            if(HttpConstant.Http_Status.Unauthorized.value()==statusCode){
                log.error(HttpConstant.Http_Status.Unauthorized.title());
            }else if(HttpConstant.Http_Status.NOT_FOUND.value()==statusCode){
                log.error(HttpConstant.Http_Status.NOT_FOUND.title());
            }else if(HttpConstant.Http_Status.INTERNAL_SERVER_ERROR.value()==statusCode){
                log.error(HttpConstant.Http_Status.INTERNAL_SERVER_ERROR.title());
            }else if(HttpConstant.Http_Status.OK.value()==statusCode){
                log.info(HttpConstant.Http_Status.OK.title());
                HttpEntity entity = httpResponse.getEntity();
                String jsonString = EntityUtils.toString(entity);
                if("[]".equals(jsonString)){
                    List<Map<String,String>> maps = new ArrayList<>();
                    Map<String,String> map = new HashMap<>();
                    map.put("sid",sid);
                    maps.add(map);
                    jsonString = JSON.toJSONString(maps);
                }
                return jsonString;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
